package {
	import adobe.utils.CustomActions;
	import event.GameEvent;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.net.URLRequest;
	import flash.ui.Mouse;
	import fs.message.Message;
	import fs.message.MessageTransmitter;
	import gs.TweenLite;
	import message.GameMessage;
	import model.AiPlayer;
	import model.BitBoard;
	import model.GameData;
	import model.PiecesDefination;
	import model.Player;
	import view.GameBoard;
	import view.Piece;
	import view.PiecesList;
	import view.ScoreLine;
	import view.Square;
	import view.TabButton;

	/**
	 * ...
	 * @author flyingSnow
	 */
	public class Main extends Sprite {
		private var _gameBoard:GameBoard;
		
		private var _mouseLayer:Sprite;
		private var _rotLayer:Sprite;
		private var _crntPiece:Piece;
		
		private var _targetDirection:int=0;
		private var _targetRotation:Number=0;
		private var _targetRotationX:Number = 0;
		
		private var _gameData:GameData;
		private var _piecesLists:Array;
		private var _crntList:PiecesList;
		//private var _tabBtns:Array;
		private var _scoreLines:Array;
		
		private var aiModule:Sprite;
		
		public function Main():void {
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			loadAi();
		}
		private function loadAi():void {
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onAiLoaded);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onAiLoadError);
			loader.load(new URLRequest("./aiModule.swf"));
			addChild(loader);
		}		
		
		private function onAiLoadError(e:IOErrorEvent):void {
			trace(e);
		}
		
		private function onAiLoaded(e:Event):void {
			(e.target as LoaderInfo).removeEventListener(Event.COMPLETE, onAiLoaded);
			AiPlayer.aiModule = (e.target as LoaderInfo).content;
			initGame();
		}
		private function initGame():void {
			addGameBoard();
			addPiecesList();
			//addTabBtns();
			addScoreLines();
			initMouse();
			addEvents();
			initGameData();
			validateMouse();
			initPiecesList();
			addAiEvent();
			startGame();
		}
		
		private function startGame():void{
			_gameData.crntPlayer.play();
		}
		
		private function addAiEvent():void {
			addEventListener(GameEvent.BEST_PATH, onGotAi);
		}
		
		private function onGotAi(e:GameEvent):void {
			if(e.args["bestPath"]!=null){
				putPiece(e.args["bestPath"]["p"],
							e.args["bestPath"]["d"],
							e.args["bestPath"]["c"],
							e.args["bestPath"]["r"]);
			}
			goOnNextFrame();
		}
		
		private function goOnNextFrame():void {
			MessageTransmitter.registerMessage(Message.ON_FRAME, onFrame);			
		}
		
		private function onFrame(msg:Message):void {
			MessageTransmitter.unregisterMessage(Message.ON_FRAME, onFrame);
			afterPutPiece();			
		}

		
		private function addScoreLines():void {
			_scoreLines = [];
			
			for (var i:int = 0; i < 4;i++ ){
				var scoreLine:ScoreLine = new ScoreLine(_scoreLines.length);
				addChild(scoreLine);
				scoreLine.x = 50;
				scoreLine.y = 670 + i * 30;
				_scoreLines.push(scoreLine);
			}
		}
		
		//private function addTabBtns():void {
			//_tabBtns = [];
			//
			//for (var i:int = 0; i < 4;i++ ){
				//var tabBtn:TabButton = new TabButton(_tabBtns.length);
				//addChild(tabBtn);
				//tabBtn.x = (_tabBtns.length%2==0)?Square.STANDARD_SIZE*BitBoard.BOARD_WIDTH+75:25;
				//tabBtn.y = (int(_tabBtns.length / 2) == 0)?25:Square.STANDARD_SIZE*BitBoard.BOARD_WIDTH+75;
				//_tabBtns.push(tabBtn);
			//}
		//}
		
		private function initPiecesList():void {
			for each(var pl:PiecesList in _piecesLists) {
				pl.visible = false;
			}
			_piecesLists[_gameData.crntPlayerIndex]["visible"] = true;
			_crntList = _piecesLists[0];
			MessageTransmitter.registerMessage(GameMessage.SELECT_PIECE, onSelectPiece);
		}
		private function addPiecesList():void {
			_piecesLists = [];
			
			for (var i:int = 0; i < 4; i++ ) {
				var pl:PiecesList = new PiecesList();
				pl.colorIndex = i;
				pl.rotation = 90;
				pl.scaleX = pl.scaleY = 0.8;
				pl.x = 900;
				pl.y = 50;
				addChild(pl);
				_piecesLists.push(pl);
			}
			//stage.addEventListener(MouseEvent.MOUSE_UP, onStop);
		}
		
		private function onStop(e:MouseEvent):void {
			//stopDrag();
		}
		
		private function onSelectPiece(msg:Message):void {
			_gameData.crntPlayer.crntPieceIndex = msg.content["index"];
			_targetDirection = 0;
			_targetDirection = (_targetDirection % 4 + 2) % 4 + (_targetDirection - _targetDirection % 4);
			targetRotation = targetRotation-180;
			validateMouse();			
		}
		
		
		private function initGameData():void {
			_gameData = new GameData();
			_gameData.getPlayer(0).startWithPoint(0, 0);
			_gameData.getPlayer(1).startWithPoint(0, BitBoard.BOARD_WIDTH-1);
			_gameData.getPlayer(2).startWithPoint(BitBoard.BOARD_WIDTH-1, BitBoard.BOARD_WIDTH-1);
			_gameData.getPlayer(3).startWithPoint(BitBoard.BOARD_WIDTH - 1, 0);
			
			for (var i:int = 0; i < 4; i++ ) {
				_gameData.getPlayer(i).addView(_piecesLists[i]);
				_gameData.getPlayer(i).addView(_scoreLines[i]);
				_gameData.getPlayer(i).updateViews();
			}
			
			_gameBoard.gameData = _gameData;
			_gameBoard.validateBoard();
		}
		
		private function initMouse():void {
			_mouseLayer = new Sprite();			
			addChild(_mouseLayer);
			_mouseLayer.mouseEnabled = false;
			
			_rotLayer = new Sprite();			
			_mouseLayer.addChild(_rotLayer);
			_rotLayer.mouseEnabled = false;
			
			_crntPiece = new Piece();
			_crntPiece.shapeArray(0, 0);
			_rotLayer.addChild(_crntPiece);
			_crntPiece.mouseChildren = _crntPiece.mouseEnabled = false;
			
			//Mouse.hide();
		}
		
		private function addEvents():void {
			//stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			MessageTransmitter.registerMessage(GameMessage.MOVE_ON_SQUARE,adjustPiecePos);
			MessageTransmitter.registerMessage(GameMessage.CLICK_SQURE,onClickSquare);
			MessageTransmitter.registerMessage(GameMessage.GAME_OVER,onGameOver);
			//MessageTransmitter.registerMessage(GameMessage.ON_PUT_PIECE,onPutPiece);
		}
		
		private function onGameOver(msg:Message):void {
			for (var i:int = 0; i < 4; i++ ) {
				TweenLite.to(_scoreLines[msg.content["res"][i]], 0.5, {y:670 + i * 30} );
			}
			TweenLite.to(_gameBoard, 0.5, {alpha:0.5} );
			
		}
		
		//private function onPutPiece(msg:Message):void {
			//_gameData.putPiece(msg.content["p"],msg.content["d"], msg.content["c"], msg.content["r"]);
			//_gameData.crntPlayer.putPiece(msg.content["p"],msg.content["d"], msg.content["c"], msg.content["r"]);
			//MessageTransmitter.registerMessage(Message.ON_FRAME, onFrame);
		//}
		//
		//private function onFrame(msg:Message):void {
			//MessageTransmitter.unregisterMessage(Message.ON_FRAME, onFrame);
			//afterPutPiece();			
		//}
		
		private function onClickSquare(msg:Message):void {
			if (_gameData.crntPlayer is AiPlayer) {
				return;
			}
			
			
			var column:int = msg.content.column;
			var row:int = msg.content.row;
			var piece:int = _gameData.crntPlayer.crntPieceIndex;
			var drct:int = _gameData.crntPlayer.crntDirection;
			
			var sizeArr:Array = PiecesDefination.PIECES_SIZE[piece][drct];			
			if (sizeArr[0] + column >= BitBoard.BOARD_WIDTH) {
				column = BitBoard.BOARD_WIDTH - sizeArr[0];
			}
			if (sizeArr[1] + row >= BitBoard.BOARD_WIDTH) {
				row = BitBoard.BOARD_WIDTH - sizeArr[1];
			}			
			if (!_gameData.canPutPiece(piece, drct, column, row)) {
				return;
			}			
			if (!_gameData.crntPlayer.canPutPiece(piece, drct, column, row)) {
				return;
			}
			_crntPiece.visible = false;
			
			putPiece(piece,drct, column, row);
			
			//setCrntList(_gameData.crntPlayerIndex);
			goOnNextFrame();
		}
		
		private function onKeyDown(e:KeyboardEvent):void {
			switch(String.fromCharCode(e.keyCode)) {
				case "A":
					turnLeft();
					break;
				case "D":
					turnRight();
					break;
				case "S":
					turnOver();
					break;
				case "P":
					trace(_gameData.crntPieces.toString("当前棋盘"));
					break;
			}
			
		}
		
		private function turnOver():void {
			if (0==(_targetDirection & (~4))) {
				_targetDirection = 4 - _targetDirection;
			}else{
				_targetDirection = 8 - _targetDirection;
			}
			
			targetRotationX += 180;
			TweenLite.to(_rotLayer, 0.3, { rotationX:_targetRotationX,onComplete:validateMouse } );
		}
		
		private function turnRight():void {
			_targetDirection = (_targetDirection % 4 + 1) % 4 + (_targetDirection - _targetDirection % 4);
			targetRotation = targetRotation+90;
			TweenLite.to(_rotLayer, 0.5, { rotation:_targetRotation,onComplete:validateMouse } );
		}
		
		private function turnLeft():void {
			_targetDirection = (_targetDirection % 4 + 3) % 4 + (_targetDirection - _targetDirection % 4);
			targetRotation = targetRotation-90;
			TweenLite.to(_rotLayer, 0.5, { rotation:_targetRotation,onComplete:validateMouse } );
		}
		
		
		//private function onMouseWheel(e:MouseEvent):void {
			//if (e.delta > 0) {
				//_gameData.crntPlayer.nextUsableIndex;//(_crntMouse + 1) % PiecesDefination.PIECES_DEF.length;
			//}else {
				//_gameData.crntPlayer.lastUsableIndex;
			//}
			//_targetDirection = 0;
			//validateMouse();
		//}
		
		private function validateMouse():void {
			_gameData.crntPlayer.crntDirection = _targetDirection;
			_crntPiece.shapeArray(_gameData.crntPlayer.crntPieceIndex, _gameData.crntPlayer.crntDirection);
			
			if(_gameData.crntPlayer.getRecentlyUsable(_gameData.crntPlayer.crntPieceIndex)){
				_crntPiece.crntColorIndex = _gameData.crntPlayerIndex;
			}else {
				_crntPiece.crntColorIndex = Square.UNABLED_INDEX;
			}
			
			
			_rotLayer.rotation = _targetRotation = 0;
			_rotLayer.rotationX = _targetRotationX = 0;
			_rotLayer.x = _rotLayer.width / 2;
			_rotLayer.y = _rotLayer.height / 2;
			
			_crntPiece.x = -_crntPiece.width / 2;
			_crntPiece.y = -_crntPiece.height / 2;
			//adjustPiecePos();
		}
		
		private function addGameBoard():void {
			_gameBoard = new GameBoard();
			_gameBoard.x = _gameBoard.y = 50;
			addChild(_gameBoard);
		}
		
		private function adjustPiecePos(msg:Message):void {
			var row:int = msg.content["row"];
			var column:int = msg.content["column"];
			var piece:int = _gameData.crntPlayer.crntPieceIndex;
			var drct:int = _gameData.crntPlayer.crntDirection;
			var sizeArr:Array = PiecesDefination.PIECES_SIZE[piece][drct];
			
			
			if (sizeArr[0] + column >= BitBoard.BOARD_WIDTH) {
				column = BitBoard.BOARD_WIDTH - sizeArr[0];
			}
			if (sizeArr[1] + row >= BitBoard.BOARD_WIDTH) {
				row = BitBoard.BOARD_WIDTH - sizeArr[1];
			}
			
			_mouseLayer.x = column * Square.STANDARD_SIZE + 50;
			_mouseLayer.y = row * Square.STANDARD_SIZE + 50;
			
			//if(row+_crntPiece.shapeArray)
		}
		
		private function setCrntList(index:int):void {
			_crntList.visible = false;
			_crntList = _piecesLists[index];
			//_crntList.update(_gameData.getPlayer(index));
			_crntList.visible = true;
		}
		
		private function afterPutPiece():void {
			_gameData.crntPlayer.updateViews();			
			if (!_gameData.nextPlayer()) {
				return;
			}		
			setCrntList(_gameData.crntPlayerIndex);
			_gameData.crntPlayer.updateViews();
			
			_gameBoard.validateBoard();
			validateMouse();
			_gameData.crntPlayer.play();
			if (!(_gameData.crntPlayer is AiPlayer)) {
				_crntPiece.visible = true;
			}
		}
		
		private function putPiece(piece:int,drct:int, column:int, row:int):void {
			_gameData.putPiece(piece,drct, column, row);
			_gameData.crntPlayer.putPiece(piece, drct, column, row);
		}
		

		
		public function get targetRotation():Number {
			return _targetRotation;
		}
		
		public function set targetRotation(value:Number):void {
			_targetRotation = value%360;
		}
		
		public function get targetRotationX():Number {
			return _targetRotationX;
		}
		
		public function set targetRotationX(value:Number):void {
			_targetRotationX = value%360;
		}

	}
	
}